﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;

namespace VitCode.Castle.Helper
{
    /// <summary>
    /// 枚舉協助類，用於獲取和緩存帶有DescriptAttribute的枚舉，並且
    /// 把它們按照枚舉所定義的DescriptAttribute的名稱表示出來
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <example>
    /// <code>
    /// using System.ComponentModel;
    /// using NUnit.Framework;
    /// using WellDell;
    /// namespace TestWellDell
    /// {
    ///   public enum IntEnum
    ///   {
    ///        [OrMemo("中文AA")] aa,
    ///        [OrMemo("中文bb")] bb,
    ///        [OrMemo("中文cc")] cc,
    ///    }
    /// public enum ByteChar :byte
    /// {
    ///		[OrMemo("紅色")] red,
    ///		[OrMemo("綠色")] green,
    ///		[OrMemo("藍色")] blue
    ///	}
    ///
    ///	[TestFixture]
    ///	public class TestEnumTypeHelper
    ///	{
    ///		[Test]
    ///		public void GetString()
    ///		{
    ///			string value = EnumTypeHelper.GetEnumDescript(typeof (IntEnum), IntEnum.aa);
    ///			Assert.IsNotNull(value);
    ///			Assert.AreEqual(value, "中文AA");
    ///
    ///			value = EnumTypeHelper.GetEnumDescript(typeof (ByteChar), ByteChar.red);
    ///			Assert.IsNotNull(value);
    ///			Assert.AreEqual(value, "紅色");
    ///			}
    ///		}
    ///	}
    /// </code>
    /// </example>
    public sealed class EnumTypeHelper
    {
        private static Hashtable Cache = new Hashtable();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="enumType"></param>
        private static void AddInCache(Type enumType)
        {
            if (Cache.ContainsKey(enumType))
            {
                return;
            }

            StringDictionary valueDescriptCollection = new StringDictionary();

            //獲得特性Description的類型資訊
            Type typeDescription = typeof (DescriptionAttribute);

            //獲得枚舉的欄位資訊（因為枚舉的值實際上是一個static的欄位的值）
            FieldInfo[] fields = enumType.GetFields();

            string key;
            string value;

            //檢索所有欄位
            foreach (FieldInfo field in fields)
            {
                //過濾掉一個不是枚舉值的，記錄的是枚舉的源類型
                if (field.FieldType.IsEnum == true)
                {
                    // 通過欄位的名字得到枚舉的值
                    // 枚舉的值如果是long的話，ToChar會有問題，但這個不在本文的討論範圍之內
                    key = Convert.ToString(enumType.InvokeMember(field.Name, BindingFlags.GetField, null, null, null));

                    //獲得這個欄位的所有自定義特性，這裏只查找Description特性
                    object[] arr = field.GetCustomAttributes(typeDescription, true);
                    if (arr.Length > 0)
                    {
                        //因為Description這個自定義特性是不允許重複的，所以我們只取第一個就可以了！
                        DescriptionAttribute aa = (DescriptionAttribute) arr[0];
                        //獲得特性的描述值，也就是‘男’‘女’等中文描述
                        value = aa.Description;
                    }
                    else
                    {
                        //如果沒有特性描述
                        value = field.Name;
                    }
                    valueDescriptCollection.Add(key, value);
                }

            }

            Cache[enumType] = valueDescriptCollection;

        }

        /// <summary>
        /// 獲取enumType的Descript表達
        /// </summary>
        /// <param name="enumType">枚舉的type</param>
        /// <param name="Value">枚舉的數值</param>
        /// <returns></returns>
        public static string GetEnumDescript(Type enumType, object Value)
        {
            StringDictionary enuCollection = (StringDictionary) Cache[enumType];
            if (enuCollection == null)
                AddInCache(enumType);
            enuCollection = (StringDictionary) Cache[enumType];
            return enuCollection[Convert.ToString(Value)];
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="enumValue"></param>
        /// <returns></returns>
        public static string GetEnumDescript(Enum enumValue)
        {
            StringDictionary enuCollection = (StringDictionary) Cache[enumValue.GetType()];
            if (enuCollection == null)
                AddInCache(enumValue.GetType());
            enuCollection = (StringDictionary) Cache[enumValue.GetType()];
            return enuCollection[Convert.ToString(enumValue)];
        }

        /// <summary>
        /// 通過字串獲取Enum的表達
        /// </summary>
        /// <param name="enumDescript"></param>
        /// <param name="enumType"></param>
        /// <returns></returns>
        public static object GetEnumValue(string enumDescript, Type enumType)
        {
            StringDictionary enuCollection = (StringDictionary) Cache[enumType];
            if (enuCollection == null)
                AddInCache(enumType);
            enuCollection = (StringDictionary) Cache[enumType];
            IEnumerator tors = enuCollection.Keys.GetEnumerator();
            while (tors.MoveNext())
            {
                string key = Convert.ToString(tors.Current);
                string value = enuCollection[key];
                if (value == enumDescript)
                {
                    return Enum.Parse(enumType, key,true);
                }
            }
            throw new ArgumentOutOfRangeException("enumDescript", enumDescript, "沒有找到對應的枚舉類型");
        }
    }
}
